home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / gr2ps / curve.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-16  |  15.0 KB  |  608 lines

  1. /* 
  2.  * This program is part of gr2ps.  It converts Gremlin's curve output to
  3.  * control vertices of Bezier Cubics, as supported by PostScript.
  4.  * Gremlin currently supports three kinds of curves:
  5.  *    (1) cubic interpolated spline with
  6.  *         i) periodic end condition, if two end points coincide
  7.  *        ii) natural end condition, otherwise
  8.  *    (2) uniform cubic B-spline with 
  9.  *         i) closed curve (no vertex interpolated), if end vertices coincide
  10.  *        ii) end vertex interpolation, otherwise
  11.  *    (3) Bezier cubics
  12.  *
  13.  * The basic idea of the conversion algorithm for the first two is
  14.  *    (1) take each curve segment's two end points as Bezier end vertices.
  15.  *    (2) find two intermediate points in the orginal curve segment
  16.  *        (with u=1/4 and u=1/2, for example).
  17.  *    (3) solve for the two intermediate control vertices.
  18.  * The conversion between Bezier Cubics of Gremlin and that of PostScript
  19.  * is straightforward.
  20.  *
  21.  * Author: Peehong Chen (phc@renoir.berkeley.edu)
  22.  * Date: 9/17/1986
  23.  */
  24.  
  25. #include <math.h>
  26. #include <stdio.h>
  27.  
  28. #define MAXPOINTS    200
  29. #define BezierMax    5
  30. #define BC1        1.0/9        /* coefficient of Bezier conversion */
  31. #define BC2        4*BC1
  32. #define BC3        3*BC2
  33. #define BC4        8*BC2
  34.  
  35. static double    Qx, Qy,
  36.         x[MAXPOINTS],
  37.         y[MAXPOINTS],
  38.         h[MAXPOINTS],
  39.         dx[MAXPOINTS],
  40.         dy[MAXPOINTS],
  41.         d2x[MAXPOINTS],
  42.         d2y[MAXPOINTS],
  43.         d3x[MAXPOINTS],
  44.         d3y[MAXPOINTS];
  45. static int    numpoints = 0;
  46.  
  47. struct point {
  48.     double    p_x, p_y;
  49. };
  50.  
  51.  
  52. /* 
  53.  * This routine copies the list of points into an array.
  54.  */
  55. static
  56. MakePoints(count, list, output)
  57.     struct point    *list;
  58.     FILE        *output;
  59. {
  60.     register int    i;
  61.  
  62.     if (count > MAXPOINTS - 1) {
  63.     error("warning: Too many points given, only first %d used.",
  64.           MAXPOINTS - 1);
  65.     count = MAXPOINTS - 1;
  66.     }
  67.  
  68.     /* Assign points from list to array for convenience of processing */
  69.     for (i = 1; i <= count; i++) {
  70.     x[i] = list[i - 1].p_x;
  71.     y[i] = list[i - 1].p_y;
  72.     }
  73.     numpoints = count;
  74. } /* end MakePoints */
  75.  
  76.  
  77. /*
  78.  * This routine converts each segment of a curve, P1, P2, P3, and P4
  79.  * to a set of two intermediate control vertices, V2 and V3, in a Bezier
  80.  * segment, plus a third vertex of the end point P4 (assuming the current
  81.  * position is P1), and then writes a PostScript command "V2 V3 V4 curveto"
  82.  * to the output file.
  83.  * The two intermediate vertices are obtained using
  84.  *    Q(u) = V1 * (1-u)^3 + V2 * 3u(1-u)^2 + V3 * 3(1-u)u^2 + V4 * u^3
  85.  * with u=1/4, and u=1/2,
  86.  *    Q(1/4) = Q2 = (x2, y2)
  87.  *    Q(1/2) = Q3 = (x3, y3)
  88.  *    V1 = P1
  89.  *    V4 = P4
  90.  * and
  91.  *    V2 = (32/9)*Q2 - (4/3)*(Q3 + V1) + (1/9)*V4
  92.  *    V3 = -(32/9)*Q2 + 4*Q3 + V1 - (4/9)*V4 
  93.  */
  94. static
  95. BezierSegment(output, x1, y1, x2, y2, x3, y3, x4, y4)
  96.     FILE    *output;
  97.     double     x1, y1, x2, y2, x3, y3, x4, y4;
  98. {
  99.     double    V2x, V2y, V3x, V3y;
  100.  
  101.     V2x = BC4 * x2 - BC3 * (x3 + x1) + BC1 * x4;
  102.     V2y = BC4 * y2 - BC3 * (y3 + y1) + BC1 * y4;
  103.     V3x = -BC4 * x2 + 4 * x3 +  x1 - BC2 * x4;
  104.     V3y = -BC4 * y2 + 4 * y3 +  y1 - BC2 * y4;
  105.     
  106.     fprintf(output,
  107.     "  %lg %lg %lg %lg %lg %lg curveto\n", V2x, V2y, V3x, V3y, x4, y4);
  108. } /* end BezierSegment */
  109.  
  110.  
  111. /* 
  112.  * This routine calculates parameteric values for use in calculating
  113.  * curves.  The values are an approximation of cumulative arc lengths 
  114.  * of the curve (uses cord * length).  For additional information, 
  115.  * see paper cited below.
  116.  *
  117.  * This is from Gremlin (called Paramaterize in gremlin),
  118.  * with minor modifications (elimination of param list)
  119.  *
  120.  */
  121. static
  122. IS_Parameterize()
  123. {
  124.     register i, j;
  125.     double t1, t2;
  126.     double u[MAXPOINTS];
  127.  
  128.     for (i=1; i<=numpoints; ++i) {
  129.     u[i] = 0.0;
  130.     for (j=1; j<i; ++j) {
  131.         t1 = x[j+1] - x[j];
  132.         t2 = y[j+1] - y[j];
  133.         u[i] += (double) sqrt((double) ((t1 * t1) + (t2 * t2)));
  134.     }
  135.     }
  136.  
  137.     for (i=1; i<numpoints; ++i)
  138.     h[i] = u[i+1] - u[i];
  139. }  /* end IS_Parameterize */
  140.  
  141.  
  142. /*
  143.  * This routine solves for the cubic polynomial to fit a spline
  144.  * curve to the the points  specified by the list of values.
  145.  * The curve generated is periodic.  The alogrithms for this 
  146.  * curve are from the "Spline Curve Techniques" paper cited below.
  147.  *
  148.  * This is from Gremlin (called PeriodicSpline in gremlin)
  149.  *
  150.  */
  151. static
  152. IS_PeriodicEnd(h, z, dz, d2z, d3z)
  153. double h[MAXPOINTS];        /* Parameterizeaterization */
  154. double z[MAXPOINTS];        /* point list */
  155. double dz[MAXPOINTS];        /* to return the 1st derivative */
  156. double d2z[MAXPOINTS];        /* 2nd derivative */
  157. double d3z[MAXPOINTS];        /* and 3rd derivative */
  158. {
  159.     double a[MAXPOINTS]; 
  160.     double b[MAXPOINTS]; 
  161.     double c[MAXPOINTS]; 
  162.     double d[MAXPOINTS]; 
  163.     double deltaz[MAXPOINTS];
  164.     double r[MAXPOINTS];
  165.     double s[MAXPOINTS];
  166.     double ftmp;
  167.     register i;
  168.  
  169.     /* step 1 */
  170.     for (i=1; i<numpoints; ++i) {
  171.     if (h[i] != 0)
  172.         deltaz[i] = (z[i+1] - z[i]) / h[i];
  173.     else
  174.         deltaz[i] = 0;
  175.     }
  176.     h[0] = h[numpoints-1];
  177.     deltaz[0] = deltaz[numpoints-1];
  178.  
  179.     /* step 2 */
  180.     for (i=1; i<numpoints-1; ++i) {
  181.     d[i] = deltaz[i+1] - deltaz[i];
  182.     }
  183.     d[0] = deltaz[1] - deltaz[0];
  184.  
  185.     /* step 3a */
  186.     a[1] = 2 * (h[0] + h[1]);
  187.     if (a[1] == 0) 
  188.     return(-1);  /* 3 consecutive knots at same point */
  189.     b[1] = d[0];
  190.     c[1] = h[0];
  191.  
  192.     for (i=2; i<numpoints-1; ++i) {
  193.     ftmp = h[i-1];
  194.     a[i] = ftmp + ftmp + h[i] + h[i] - (ftmp * ftmp)/a[i-1];
  195.         if (a[i] == 0) 
  196.         return(-1);  /* 3 consec knots at same point */
  197.     b[i] = d[i-1] - ftmp * b[i-1]/a[i-1];
  198.     c[i] = -ftmp * c[i-1]/a[i-1];
  199.     }
  200.  
  201.     /* step 3b */
  202.     r[numpoints-1] = 1;
  203.     s[numpoints-1] = 0;
  204.     for (i=numpoints-2; i>0; --i) {
  205.     r[i] = -(h[i] * r[i+1] + c[i])/a[i];
  206.     s[i] = (6 * b[i] - h[i] * s[i+1])/a[i];
  207.     }
  208.  
  209.     /* step 4 */
  210.     d2z[numpoints-1] = (6 * d[numpoints-2] - h[0] * s[1] 
  211.                - h[numpoints-1] * s[numpoints-2]) 
  212.              / (h[0] * r[1] + h[numpoints-1] * r[numpoints-2] 
  213.             + 2 * (h[numpoints-2] + h[0]));
  214.     for (i=1; i<numpoints-1; ++i) {
  215.     d2z[i] = r[i] * d2z[numpoints-1] + s[i];
  216.     }
  217.     d2z[numpoints] = d2z[1];
  218.  
  219.     /* step 5 */
  220.     for (i=1; i<numpoints; ++i) {
  221.     dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6;
  222.     if (h[i] != 0)
  223.         d3z[i] = (d2z[i+1] - d2z[i])/h[i];
  224.     else
  225.         d3z[i] = 0;
  226.     }
  227.  
  228.     return(0);
  229. }  /* end IS_PeriodicEnd */
  230.  
  231.  
  232. /*
  233.  * This routine solves for the cubic polynomial to fit a spline
  234.  * curve from the points specified by the list of values.  The alogrithms for
  235.  * this curve are from the "Spline Curve Techniques" paper cited below.
  236.  *
  237.  * This is from Gremlin (called NaturalEndSpline in gremlin)
  238.  *
  239.  */
  240. static
  241. IS_NaturalEnd(h, z, dz, d2z, d3z)
  242. double h[MAXPOINTS];        /* parameterization */
  243. double z[MAXPOINTS];        /* point list */
  244. double dz[MAXPOINTS];        /* to return the 1st derivative */
  245. double d2z[MAXPOINTS];        /* 2nd derivative */
  246. double d3z[MAXPOINTS];        /* and 3rd derivative */
  247. {
  248.     double a[MAXPOINTS]; 
  249.     double b[MAXPOINTS]; 
  250.     double d[MAXPOINTS]; 
  251.     double deltaz[MAXPOINTS];
  252.     double ftmp;
  253.     register i;
  254.  
  255.     /* step 1 */
  256.     for (i=1; i<numpoints; ++i) {
  257.     if (h[i] != 0)
  258.         deltaz[i] = (z[i+1] - z[i]) / h[i];
  259.     else
  260.         deltaz[i] = 0;
  261.     }
  262.     deltaz[0] = deltaz[numpoints-1];
  263.  
  264.     /* step 2 */
  265.     for (i=1; i<numpoints-1; ++i) {
  266.     d[i] = deltaz[i+1] - deltaz[i];
  267.     }
  268.     d[0] = deltaz[1] - deltaz[0];
  269.  
  270.     /* step 3 */
  271.     a[0] = 2 * (h[2] + h[1]);
  272.     if (a[0] == 0)        /* 3 consec knots at same point */
  273.     return(-1);
  274.     b[0] = d[1];
  275.  
  276.     for (i=1; i<numpoints-2; ++i) {
  277.     ftmp = h[i+1];
  278.     a[i] = ftmp + ftmp + h[i+2] + h[i+2] - (ftmp * ftmp) / a[i-1];
  279.     if (a[i] == 0)        /* 3 consec knots at same point */
  280.         return(-1);
  281.     b[i] = d[i+1] - ftmp * b[i-1]/a[i-1];
  282.     }
  283.  
  284.     /* step 4 */
  285.     d2z[numpoints] = d2z[1] = 0;
  286.     for (i=numpoints-1; i>1; --i) {
  287.     d2z[i] = (6 * b[i-2] - h[i] *d2z[i+1])/a[i-2];
  288.     }
  289.  
  290.     /* step 5 */
  291.     for (i=1; i<numpoints; ++i) {
  292.     dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6;
  293.     if (h[i] != 0)
  294.         d3z[i] = (d2z[i+1] - d2z[i])/h[i];
  295.     else
  296.         d3z[i] = 0;
  297.     }
  298.  
  299.     return(0);
  300. }  /* end IS_NaturalEnd */
  301.  
  302.  
  303. /* 
  304.  * Use the same algorithm Gremlin uses to interpolate a given
  305.  * set of points, as described in ``Spline Curve Techniques,''
  306.  * by Pattrick Baudelaire, Robert M. Flegal, and Robert F. Sproull,
  307.  * Xerox PARC Tech Report No. 78CSL-059.
  308.  */
  309. static
  310. IS_Initialize(count, list, output)
  311.     struct point    *list;
  312.     FILE        *output;
  313. {
  314.     MakePoints(count, list, output);
  315.     IS_Parameterize();
  316.  
  317.     /* Solve for derivatives of the curve at each point 
  318.        separately for x and y (parametric). */
  319.  
  320.     if ((x[1] == x[numpoints]) && (y[1] == y[numpoints])) { /* closed curve */
  321.     IS_PeriodicEnd(h, x, dx, d2x, d3x);
  322.     IS_PeriodicEnd(h, y, dy, d2y, d3y);
  323.     }
  324.     else {
  325.     IS_NaturalEnd(h, x, dx, d2x, d3x);
  326.     IS_NaturalEnd(h, y, dy, d2y, d3y);
  327.     }
  328. }
  329.  
  330.  
  331. /* 
  332.  * This routine converts cubic interpolatory spline to Bezier control vertices
  333.  */
  334. static
  335. IS_Convert(output)
  336. FILE    *output;
  337. {
  338.     double t, t2, t3, x2, y2, x3, y3;
  339.     register j, j1;
  340.  
  341.     for (j = 1; j < numpoints; ++j) {
  342.     t = .25 * h[j];
  343.     t2 = t * t;
  344.     t3 = t2 * t;
  345.     x2 = x[j] + t * dx[j] + t2 * d2x[j]/2.0 + t3 * d3x[j]/6.0;
  346.     y2 = y[j] + t * dy[j] + t2 * d2y[j]/2.0 + t3 * d3y[j]/6.0;
  347.     
  348.     t = 2 * t;
  349.     t2 = t * t;
  350.     t3 = t2 * t;
  351.     x3 = x[j] + t * dx[j] + t2 * d2x[j]/2.0 + t3 * d3x[j]/6.0;
  352.     y3 = y[j] + t * dy[j] + t2 * d2y[j]/2.0 + t3 * d3y[j]/6.0;
  353.     
  354.     j1 = j + 1;
  355.         BezierSegment(output, x[j], y[j], x2, y2, x3, y3, x[j1], y[j1]);
  356.     }
  357. } /* end IS_Convert */
  358.  
  359.  
  360. /*
  361.  * This routine converts cubic interpolatory splines to Bezier cubics.
  362.  */
  363. makecurve(count, list, output)
  364.     struct point    *list;
  365.     FILE        *output;
  366. {
  367.     IS_Initialize(count, list, output);
  368.  
  369.     fprintf(output, "newpath %lg %lg moveto\n", x[1], y[1]);
  370.     IS_Convert(output);
  371.     fputs("stroke\n", output);
  372.     
  373.     return (0);
  374. } /* end makecurve  */
  375.  
  376.  
  377.  
  378. /*
  379.  * This routine computes a point in B-spline segment, given i, and u.
  380.  * Details of this algorithm can be found in the tech. report cited below.
  381.  */
  382. static
  383. BS_ComputePoint(i, u)
  384. int i;
  385. float u;
  386. {
  387.     float u2, u3, b_2, b_1, b0, b1;
  388.     register i1, i_2, i_1;
  389.  
  390.     i1  = i + 1;
  391.     i_1 = i - 1;
  392.     i_2 = i - 2;
  393.  
  394.     u2 = u * u;
  395.     u3 = u2 * u;
  396.     b_2 = (1 - 3*u + 3*u2 - u3) / 6.0;
  397.     b_1 = (4 - 6*u2 + 3*u3) / 6.0;
  398.     b0  = (1 + 3*u + 3*u2 - 3*u3) / 6.0;
  399.     b1  = u3 / 6.0;
  400.  
  401.     Qx = b_2 * x[i_2] + b_1 * x[i_1] + b0 * x[i] + b1 * x[i1];
  402.     Qy = b_2 * y[i_2] + b_1 * y[i_1] + b0 * y[i] + b1 * y[i1];    
  403. } /* end BS_ComputePoint */
  404.  
  405.  
  406. /*
  407.  * This routine initializes the array of control vertices
  408.  * We consider two end conditions here:
  409.  *   (1) closed curve -- C2 continuation and end vertex not interpolated, i.e. 
  410.  *        V[0] = V[n-1], and
  411.  *        V[n+1] = V[2].
  412.  *   (2) open curve -- end vertex interpolation, i.e.
  413.  *        V[0] = 2*V[1] - V[2], and
  414.  *        V[n+1] = 2*V[n] - V[n-1].
  415.  * Details of uniform cubic B-splines, including other end conditions
  416.  * and important properties can be found in Chapters 4-5 of
  417.  * Richard H. Bartels and Brian A. Barsky,
  418.  * "An Introduction to the Use of Splines in Computer Graphics",
  419.  * Tech. Report CS-83-136, Computer Science Division,
  420.  * University of California, Berkeley, 1984.
  421.  */
  422. BS_Initialize(count, list, output)
  423.     struct point    *list;
  424.     FILE        *output;
  425. {
  426.     register n_1, n1;
  427.  
  428.     MakePoints(count, list, output);
  429.  
  430.     n_1 = numpoints - 1;
  431.     n1  = numpoints + 1;
  432.   
  433.     if ((x[1] == x[numpoints]) && (y[1] == y[numpoints])) { /* closed curve */
  434.     x[0] = x[n_1];                /* V[0] */
  435.     y[0] = y[n_1];
  436.     x[n1] = x[2];                /* V[n+1] */
  437.     y[n1] = y[2];
  438.     }
  439.     else {                /* end vertex interpolation */
  440.     x[0] = 2*x[1] - x[2];            /* V[0] */
  441.     y[0] = 2*y[1] - y[2];
  442.     x[n1] = 2*x[numpoints] - x[n_1];        /* V[n+1] */
  443.     y[n1] = 2*y[numpoints] - y[n_1];
  444.     }
  445. } /* end BS_Initialize */
  446.  
  447.  
  448. /* 
  449.  * This routine converts uniform cubic B-spline to Bezier control vertices
  450.  */
  451. static
  452. BS_Convert(output)
  453.     FILE    *output;
  454. {
  455.     double x1, y1, x2, y2, x3, y3;
  456.     register i;
  457.  
  458.     for (i = 2; i <= numpoints; i++) {
  459.     BS_ComputePoint(i, 0.0);
  460.     x1 = Qx;
  461.     y1 = Qy;
  462.     BS_ComputePoint(i, 0.25);
  463.     x2 = Qx;
  464.     y2 = Qy;
  465.     BS_ComputePoint(i, 0.5);
  466.     x3 = Qx;
  467.     y3 = Qy;
  468.     BS_ComputePoint(i, 1.0);
  469.  
  470.         BezierSegment(output, x1, y1, x2, y2, x3, y3, Qx, Qy);
  471.     }
  472. } /* end BS_Convert */
  473.  
  474.  
  475. /*
  476.  * This routine converts B-spline to Bezier Cubics
  477.  */
  478. makebspline(count, list, output)
  479.     struct point    *list;
  480.     FILE        *output;
  481. {
  482.     BS_Initialize(count, list, output);
  483.  
  484.     BS_ComputePoint(2, 0.0);
  485.     fprintf(output, "newpath %lg %lg moveto\n", Qx, Qy);
  486.     BS_Convert(output);
  487.     fputs("stroke\n", output);
  488.  
  489.     return (0);
  490. } /* makebspline */
  491.  
  492.  
  493. /* 
  494.  * This routine copies the offset between two consecutive control points
  495.  * into an array.  That is,
  496.  *     O[i] = (x[i], y[i]) = V[i+1] - V[i],
  497.  * for i=1 to N-1, where N is the number of points given.
  498.  * The starting end point (V[1]) is saved in (Qx, Qy).
  499.  */
  500. static
  501. BZ_Offsets(count, list, output)
  502.     struct point    *list;
  503.     FILE        *output;
  504. {
  505.     register    i;
  506.     register    double    Lx, Ly;
  507.  
  508.     if (count > MAXPOINTS - 1) {
  509.     error("warning: Too many points given, only first %d used.",
  510.           MAXPOINTS - 1);
  511.     count = MAXPOINTS - 1;
  512.     }
  513.  
  514.     /* Assign offsets btwn points to array for convenience of processing */
  515.     Qx = Lx = list[0].p_x;
  516.     Qy = Ly = list[0].p_y;
  517.     for (i = 1; i < count; i++) {
  518.     x[i] = list[i].p_x - Lx;
  519.     y[i] = list[i].p_y - Ly;
  520.     Lx = list[i].p_x;
  521.     Ly = list[i].p_y;
  522.     }
  523.     numpoints = count;
  524. }
  525.  
  526.  
  527. /* 
  528.  * This routine contructs paths of piecewise continuous Bezier cubics
  529.  * in PostScript based on the given set of control vertices.
  530.  * Given 2 points, a stringht line is drawn.
  531.  * Given 3 points V[1], V[2], and V[3], a Bezier cubic segment
  532.  * of (V[1], (V[1]+V[2])/2, (V[2]+V[3])/2, V[3]) is drawn.
  533.  * In the case when N (N >= 4) points are given, N-2 Bezier segments will
  534.  * be drawn, each of which (for i=1 to N-2) is translated to PostScript as
  535.  *    Q+O[i]/3  Q+(3*O[i]+O[i+1])/6  K+O[i+1]/2  curveto,
  536.  * where
  537.  *    Q is the current point,
  538.  *    K is the continuation offset = Qinitial + Sigma(1, i)(O[i])
  539.  * Note that when i is 1, the initial point
  540.  *    Q = V[1].
  541.  * and when i is N-2, the terminating point
  542.  *    K+O[i+1]/2 = V[N].
  543.  */
  544. static
  545. BZ_Convert(output)
  546.     FILE    *output;
  547. {
  548.     register    i, i1;
  549.     double    x1, y1, x2, y2, x3, y3, Kx, Ky;
  550.     
  551.     if (numpoints == 2) {
  552.     fprintf(output, "  %lg %lg rlineto\n", x[1], y[1]);
  553.     return;
  554.     }
  555.     if (numpoints == 3) {
  556.     x1 = Qx + x[1];
  557.     y1 = Qy + y[1];
  558.     x2 = x1 + x[2];
  559.     y2 = y1 + y[2];
  560.         fprintf(output,"  %lg %lg %lg %lg %lg %lg curveto\n",
  561.         (Qx+x1)/2.0, (Qy+y1)/2.0, (x1+x2)/2.0, (y1+y2)/2.0, x2, y2);
  562.     return;
  563.     }
  564.   
  565.     /* numpoints >= 4 */
  566.     Kx = Qx + x[1];
  567.     Ky = Qy + y[1];
  568.     x[1] = 2 * x[1];
  569.     y[1] = 2 * y[1];
  570.     i = numpoints - 1;
  571.     x[i] = 2 * x[i];
  572.     y[i] = 2 * y[i];
  573.     i1 = 2;
  574.     for (i = 1; i <= numpoints-2; i++) {
  575.     x1 = Qx + x[i]/3;
  576.     y1 = Qy + y[i]/3;
  577.     x2 = Qx + (3*x[i] + x[i1])/6;
  578.     y2 = Qy + (3*y[i] + y[i1])/6;
  579.     x3 = Kx + x[i1]/2;
  580.     y3 = Ky + y[i1]/2;
  581.         fprintf(output, "  %lg %lg %lg %lg %lg %lg curveto\n",
  582.                 x1, y1, x2, y2, x3, y3);
  583.     Qx = x3;
  584.     Qy = y3;
  585.     Kx = Kx + x[i1];
  586.     Ky = Ky + y[i1];
  587.     i1++;
  588.     }
  589. } /* end BZ_Convert */
  590.  
  591.  
  592. /*
  593.  * This routine draws piecewise continuous Bezier cubics based on
  594.  * the given list of control vertices.
  595.  */
  596. makebezier(count, list, output)
  597.     struct point    *list;
  598.     FILE        *output;
  599. {
  600.     BZ_Offsets(count, list, output);
  601.  
  602.     fprintf(output, "newpath %lg %lg moveto\n", Qx, Qy);
  603.     BZ_Convert(output);
  604.     fputs("stroke\n", output);
  605.     
  606.     return (0);
  607. }
  608.